package org.bdware.irs.backend.servicesImpl;

import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.nimbusds.jose.jwk.JWK;
import org.apache.log4j.Logger;
import org.bdware.irp.client.IrpClientImpl;
import org.bdware.irp.exception.IrpClientException;
import org.bdware.irp.irplib.util.GlobalUtils;
import org.bdware.irp.stateinfo.StateInfoBase;
import org.bdware.irp.stateinfo.UserStateInfo;
import org.bdware.irs.IrsBootWithTcp;
import org.bdware.irs.IrsConfig;
import org.bdware.irs.backend.dto.Stat;
import org.bdware.irs.backend.services.IrsService;
import org.bdware.irs.server.http.IrsHandler;
import org.bdware.irs.server.http.IrsMain;
import org.bdware.irs.server.tcp.IrpServerMain;
import org.bdware.irs.backend.dto.Organization;
import org.rocksdb.RocksDBException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/*
irs backend和irs server同时启动，这样就可以直接同时操作存储irs的数据库
未完成
 */
@Service
public class IrsServiceStandAloneImpl implements IrsService {
    BDIrsStorageImpl bdIrsStorage;
    static Logger logger = Logger.getLogger(IrsServiceStandAloneImpl.class);

    public IrpClientImpl client;


    public IrsServiceStandAloneImpl() throws InterruptedException {
        int count = 0;
        while (IrpServerMain.getIrsHandle() == null) {
            logger.info("wait for DOIP Service initialization");
            Thread.sleep(1000);
            if (count++ > 5) break;
        }

        if (IrpServerMain.getIrsHandle() == null) {
            logger.error("IRS not initialized.");
        }

        bdIrsStorage = IrpServerMain.getStore();

        try{
            JWK jwk = GlobalUtils.loadKeysFromJWKFile("./keys/jwk/dou.TEST.jwk");
            logger.info("load the jwk finish");
            client = new IrpClientImpl(jwk, IrsBootWithTcp.irsConfig.prefix, IrsBootWithTcp.irsConfig.grsAddress);
            client.connect(IrsBootWithTcp.irsConfig.grsAddress);
        }catch(Exception e){
            e.printStackTrace();
        }

    }

    @Override
    public StateInfoBase resolve(String doi) {
        StateInfoBase saveStateInfo = bdIrsStorage.getStateInfoByID(doi);
        return saveStateInfo;
    }

    @Override
    public boolean registerUser(UserStateInfo userStateInfo) {
        return bdIrsStorage.saveStateInfo(userStateInfo);
    }

    @Override
    public boolean updateUser(UserStateInfo userStateInfo) {
        StateInfoBase save = bdIrsStorage.updateStateInfo(userStateInfo);
        if (save == null)
            return false;
        return true;
    }

    @Override
    public UserStateInfo getCurrentUser(String doi) {
        StateInfoBase saveStateInfo = bdIrsStorage.getStateInfoByID(doi);
        if (saveStateInfo == null)
            return null;
        UserStateInfo userStateInfo = UserStateInfo.fromStateInfoBase(saveStateInfo);
        return userStateInfo;
    }

    @Override
    public List getBindedRepoAndRegs() {
        return bdIrsStorage.getBindedRepoAndRegs();
    }

    @Override
    public Set getAllUsers() {
        return bdIrsStorage.getAllUsers();
    }

    @Override
    public List getAllStateInfos() {
        return bdIrsStorage.getAllStateInfos();
    }

    @Override
    public boolean isManager(String doi, String role) {
        List repos = bdIrsStorage.getBindedRepoAndRegs();
        logger.info(new Gson().toJson(repos));

        for (Object repoInfoStr : repos) {
            StateInfoBase repo = StateInfoBase.fromJson((String) repoInfoStr);
            if (doi != null && doi.equals(repo.getHandleValues().get("owner").getAsString()) && role != null && role.equals(repo.getHandleValues().get("type").getAsString())) {
                return true;
            }
        }
        return false;
    }

    @Override
    public String getValue(String key) {
        try {
            byte[] value = bdIrsStorage.db.get(key.getBytes());
            if (value != null) {
                return new String(value);
            }
        } catch (RocksDBException e) {
            e.printStackTrace();
        }
        return null;

    }

    public boolean saveOrganization(Organization organization) {
        logger.info(new Gson().toJson(organization));
        try {
            boolean result = client.allocatePrefix(organization.toStateInfoBase1());
        } catch (IrpClientException e) {
            e.printStackTrace();
            return false;
        }
        return bdIrsStorage.saveOrganization(organization);
    }

    public boolean updateOrganization(Organization organization) {
        return bdIrsStorage.updateOrganization(organization);
    }

    public boolean deleteOrganization(Organization organization) {
        return bdIrsStorage.deleteOrganization(organization);
    }

    public Organization getOrganization(String doi) {
        return bdIrsStorage.getOrganization(doi);
    }

    public List<Organization> getAllOrganization() {
        return bdIrsStorage.getAllOrganization();
    }

    public Stat getStat(){
        return bdIrsStorage.getStat();
    }
}
